using NICWebApi.Extensions.Caching.Interfaces;

namespace NICWebApi.Extensions.Caching.Attributes;

/// <summary>
/// 标记方法执行后需要更新缓存
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class CacheUpdateAttribute : AbstractInterceptorAttribute
{
    /// <summary>
    /// 缓存键模板，支持参数占位符 {id}
    /// </summary>
    public string Key { get; set; }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="key">缓存键模板</param>
    public CacheUpdateAttribute(string key = null)
    {
        Key = key;
    }

    /// <summary>
    /// 执行拦截
    /// </summary>
    /// <param name="context"></param>
    /// <param name="next"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentException"></exception>
    public override async Task Invoke(AspectContext context, AspectDelegate next)
    {
        bool isAsync = context.IsAsync();
        if (context.ServiceMethod.ReturnType == typeof(void) || isAsync && !context.ServiceMethod.ReturnType.IsGenericType)
        {
            throw new ArgumentException("method cannot return void");
        }

        var cacheKeyGenerator = context.ServiceProvider.GetRequiredService<ISimpleCacheKeyGenerator>();

        var cacheService = context.ServiceProvider.GetRequiredService<ISimpleCacheService>();

        var cacheKey = cacheKeyGenerator.GeneratePatternKey(Key);

        await next(context);

        object targetReturn = context.IsAsync() ? await context.UnwrapAsyncReturnValue() : context.ReturnValue;

        var isExists = await cacheService.ExistsAsync(cacheKey);

        await cacheService.SetAsync(cacheKey, targetReturn);
    }
}